package tools

import (
	"bufio"
	"crypto/md5"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"math"
	"math/rand"
	"net"
	"net/url"
	"os"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
)

func Md5(str string) string {
	h := md5.New()
	_, _ = io.WriteString(h, str)
	return fmt.Sprintf("%x", h.Sum(nil))
}

// UrlReset 重构url参数
func UrlReset(originUrl string, parameters map[string]string) (dstUrl string, err error) {
	resUrl, err := url.Parse(originUrl)
	if err != nil {
		return
	}
	params := url.Values{}
	for key, val := range parameters {
		params.Set(key, val)
	}
	if resUrl.RawQuery == "" {
		resUrl.RawQuery = params.Encode()
	} else {
		resUrl.RawQuery = resUrl.RawQuery + "&" + params.Encode()
	}
	dstUrl = resUrl.String()
	return
}

// GetRandomString 随机字符串
func GetRandomString(n int) string {
	str := "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	bytes := []byte(str)
	var result []byte
	for i := 0; i < n; i++ {
		result = append(result, bytes[rand.Intn(len(bytes))])
	}
	return string(result)
}

// GetRandomNumberStr 随机数字字符串
func GetRandomNumberStr(n int) string {
	rand.Seed(time.Now().UnixNano())
	str := ""
	for i := 0; i < n; i++ {
		str += strconv.Itoa(rand.Intn(10))
	}
	return str
}

// SubStr 截取字符串，支持多字节字符 start：起始下标，负数从从尾部开始，最后一个为-1  length：截取长度，负数表示截取到末尾
func SubStr(str string, start int, length int) (result string) {
	s := []rune(str)
	total := len(s) // 全部字数
	if total == 0 {
		return
	}
	// 允许从尾部开始计算
	if start < 0 {
		start = total + start
		if start < 0 {
			return
		}
	}
	if start > total {
		return
	}
	// 到末尾
	end := total
	if length == 0 {
		end = total
	} else if length < 0 {
		end = total + length
	} else {
		end = start + length
	}
	if end <= start {
		return
	}
	if end > total {
		result = string(s[start:])
	} else {
		result = string(s[start:end])
	}
	return
}

// JoinIntArray 分隔符拼接数组
func JoinIntArray(arr []int, separator string) string {
	if len(arr) > 0 {
		str := ""
		for _, v := range arr {
			str += fmt.Sprintf("%v%v", v, separator)
		}
		return SubStr(str, 0, -1)
	}
	return ""
}

// GetRandAreaNumber 在范围内取随机数
func GetRandAreaNumber(min int, max int) int {
	return rand.Intn(max-min+1) + min
}

// SignFromMapString 生成签名
func SignFromMapString(params interface{}, appSecret string) (string, error) {
	byteData, _ := json.Marshal(params)
	var data map[string]string
	err := json.Unmarshal(byteData, &data)
	if err != nil {
		return "", err
	}
	v := url.Values{}
	for key, value := range data {
		v.Set(key, value)
	}
	queryString := v.Encode()
	queryString = strings.ToLower(queryString + "&app_secret=" + appSecret)
	sign := Md5(queryString)
	return sign, nil

}

// IntSliceToString 逗号拼接数字
func IntSliceToString(nums []int) string {
	strSlice := make([]string, len(nums))
	for i, num := range nums {
		strSlice[i] = strconv.Itoa(num)
	}
	return strings.Join(strSlice, ",")
}

// Filter 切片过滤 返回符合条件的新切片
func Filter[T any](slice []T, condition func(T) bool) []T {
	var filtered []T
	for _, item := range slice {
		if condition(item) {
			filtered = append(filtered, item)
		}
	}
	return filtered
}

// SliceInsert 切片指定位置插入元素
func SliceInsert[T any](a []T, deleteIndex int, b ...T) ([]T, error) {
	var res []T
	if deleteIndex < 0 || deleteIndex > len(a) {
		return a, errors.New("deleteIndex exceeded")
	}
	// 插入元素
	left := a[0:deleteIndex]
	right := a[deleteIndex:]
	res = make([]T, 0, len(a)+len(b))
	b = append(b, right...) // 注意,不可以这样顺序 append(left,b,right)
	res = append(left, b...)
	return res, nil
}

// SliceDelete 切片指定位置删除元素
func SliceDelete[T any](a []T, deleteIndex int) ([]T, error) {
	var res []T
	if deleteIndex < 0 || deleteIndex >= len(a) {
		return a, errors.New("deleteIndex exceeded")
	}
	// 删除元素
	left := a[0:deleteIndex]
	right := a[(deleteIndex + 1):]
	res = make([]T, 0, len(a)-1)
	res = append(left, right...)
	return res, nil
}

// SliceReverse 切片倒置
func SliceReverse[T any](a *[]T) {
	length := len(*a)
	for i := 0; i < length/2; i++ {
		(*a)[i], (*a)[length-i-1] = (*a)[length-i-1], (*a)[i]
	}
}

// StrPad 字符串补位
func StrPad(str, pad, pos string, n int) string {
	l := len(str)
	if l >= n {
		return str
	}
	padStr := ""
	for i := 0; i < n-l; i++ {
		padStr += pad
	}

	if pos == "left" {
		str = padStr + str
	}
	if pos == "right" {
		str = str + padStr
	}
	return str
}

// GetExcelCols 获取excel列 A ~ AZ
func GetExcelCols() []string {
	return []string{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW", "AX", "AY", "AZ"}
}

// MaxInt 最大值
func MaxInt(slice []int) (value, index int) {
	value = 0
	index = -1
	if len(slice) == 0 {
		return
	}
	value = slice[0]
	index = 0
	for k, item := range slice {
		if item > value {
			value = item
			index = k
		}
	}
	return
}

// MinInt 最小值
func MinInt(slice []int) (value, index int) {
	value = 0
	index = -1
	if len(slice) == 0 {
		return
	}
	value = slice[0]
	index = 0
	for k, item := range slice {
		if item < value {
			value = item
			index = k
		}
	}
	return
}

// StrToIntSlice 字符串转[]int
func StrToIntSlice(str string) []int {
	a := make([]int, 0)
	s := strings.Split(str, ",")
	for _, v := range s {
		if v != "" {
			n, _ := strconv.Atoi(v)
			a = append(a, n)
		}
	}
	return a
}

// StrToIntMap 字符串转map[int]
func StrToIntMap(str string) map[int]bool {
	m := make(map[int]bool)
	strArr := strings.Split(str, ",")
	for _, v := range strArr {
		if v != "" {
			n, _ := strconv.Atoi(v)
			m[n] = true
		}
	}
	return m
}

// StrToStringMap 字符串转map[string]
func StrToStringMap(str string) map[string]bool {
	m := make(map[string]bool)
	strArr := strings.Split(str, ",")
	for _, v := range strArr {
		if v != "" {
			m[v] = true
		}
	}
	return m
}

// IntInArray 判断int是否在[]int中
func IntInArray(a int, b []int) bool {
	for _, val := range b {
		if val == a {
			return true
		}
	}
	return false
}
func StrInArray(a string, b []string) bool {
	for _, val := range b {
		if val == a {
			return true
		}
	}
	return false
}

// GetMacAddr 获取本机Mac地址
func GetMacAddr() (macAddrs []string) {
	netInterfaces, err := net.Interfaces()
	if err != nil {
		return macAddrs
	}
	for _, netInterface := range netInterfaces {
		macAddr := netInterface.HardwareAddr.String()
		if len(macAddr) == 0 {
			continue
		}

		macAddrs = append(macAddrs, macAddr)
	}
	return macAddrs
}

// GetIPs 获取本机IP地址
func GetIPs() (ips []string) {
	interfaceAddr, err := net.InterfaceAddrs()
	if err != nil {
		return ips
	}
	for _, address := range interfaceAddr {
		ipNet, isValidIpNet := address.(*net.IPNet)
		if isValidIpNet && !ipNet.IP.IsLoopback() {
			if ipNet.IP.To4() != nil {
				ips = append(ips, ipNet.IP.String())
			}
		}
	}
	return ips
}

// Pause 暂停程序
func Pause() {
	fmt.Println("按任意键退出...")
	reader := bufio.NewReader(os.Stdin)
	_, _, _ = reader.ReadRune()
	//fmt.Println("程序已退出")
}

// IsValidUTF8 检查字符串是否为UTF-8编码
func IsValidUTF8(s string) bool {
	return utf8.ValidString(s)
}

// HasDuplicatesStr 检查字符串切片中是否存在重复项
func HasDuplicatesStr(items []string) bool {
	seen := make(map[string]struct{}) // 使用空结构体节省空间
	for _, item := range items {
		if _, exists := seen[item]; exists {
			return true // 找到重复项
		}
		seen[item] = struct{}{} // 标记为已见
	}
	return false // 没有找到重复项
}

// FormatFloat 格式化浮点数
func FormatFloat(f float64) string {
	if f == math.Trunc(f) {
		// 没有小数部分，只返回整数部分
		return fmt.Sprintf("%.0f", f)
	}
	// 有小数部分，保留两位小数
	return fmt.Sprintf("%.2f", f)
}

// RoundFloat 舍入
func RoundFloat(val float64, precision int) float64 {
	ratio := math.Pow(10, float64(precision))
	return math.Round(val*ratio) / ratio
}
